package service

import (
	"bytes"
	"context"
	"encoding/json"
	"fx_swift_forex/api"
	"fx_swift_forex/internal/model"
	"fx_swift_forex/pkg/code"
	"fx_swift_forex/pkg/global"
	"fx_swift_forex/pkg/internalerrors"
	"github.com/spf13/cast"
	"mime/multipart"
)

type IBalanceSrv interface {
	// 获取余额
	GetBalance(ctx context.Context, currency, onBehalfOf string) (*api.GetCurrencyToBalanceRes, error)

	// 获取对应币种信息
	GetCurrencies(ctx context.Context) (*api.GetCurrenciesRes, error)

	// 交易记录
	GetTransactionRecord(ctx context.Context, req api.TransactionsRecordReq) (*api.TransactionsRecordRes, error)

	// 余额查询
	FindBalance(ctx context.Context, onBehalfOf string) (*api.FindBalanceRes, error)

	TopUpMargin(ctx context.Context, req *api.TopUpMarginReq) (*api.TopUpMarginRes, error)
}

type balanceSrv struct {
}

func NewBalanceSrv() IBalanceSrv {
	return &balanceSrv{}
}

// 获取余额
func (b *balanceSrv) GetBalance(ctx context.Context, currency, onBehalfOf string) (*api.GetCurrencyToBalanceRes, error) {
	var (
		url    = global.ViperObj.GetString("forex.baseUrl") + "/v2/balances/"
		err    error
		body   []byte
		obj    *api.GetCurrencyToBalanceRes
		params = make(map[string]string)
	)
	if len(onBehalfOf) > 0 {
		params["on_behalf_of"] = onBehalfOf
	}
	body, err = GetRequestToCC(ctx, url+currency, params)
	if err != nil {
		return nil, internalerrors.New(code.ErrUnknown, err.Error())
	}
	err = json.Unmarshal(body, &obj)
	if err != nil {
		return nil, err
	}
	return obj, err
}

// 获取对应币种信息
func (b *balanceSrv) GetCurrencies(ctx context.Context) (*api.GetCurrenciesRes, error) {
	var (
		url           = global.ViperObj.GetString("forex.baseUrl") + "/v2/reference/currencies"
		err           error
		body          []byte
		obj           *api.GetCurrenciesRes
		fCurrencyList = make([]*model.ForexCurrency, 0)
	)
	body, err = GetRequestToCC(ctx, url, nil)
	if err != nil {
		return nil, internalerrors.New(code.ErrUnknown, err.Error())
	}
	err = json.Unmarshal(body, &obj)
	if err != nil {
		return nil, err
	}
	if err = global.GFDB.Model("forex_currency").Where("1=1").Scan(&fCurrencyList); err != nil {
		return nil, internalerrors.New(code.ErrUnknown, err.Error())
	}
	mapContainer := make(map[string]*model.ForexCurrency, 0)
	for _, value := range fCurrencyList {
		mapContainer[value.CurrencyCode] = value
	}
	for _, value := range obj.Currencies {
		if _, ok := mapContainer[value.Code]; ok {
			value.Image = mapContainer[value.Code].Image
			value.CurrencyName = mapContainer[value.Code].CurrencyName
		}
	}
	return obj, err
}

// 交易记录
func (b *balanceSrv) GetTransactionRecord(ctx context.Context, req api.TransactionsRecordReq) (*api.TransactionsRecordRes, error) {
	var (
		url    = global.ViperObj.GetString("forex.baseUrl") + "/v2/transactions/find"
		err    error
		body   []byte
		obj    *api.TransactionsRecordRes
		params = make(map[string]string)
	)
	params["status"] = req.Status
	params["currency"] = req.Currency
	params["settles_at_to"] = req.SettlesAtTo
	params["settles_at_from"] = req.SettlesAtFrom
	params["page"] = cast.ToString(req.Page)
	params["per_page"] = cast.ToString(req.PageNum)
	body, err = GetRequestToCC(ctx, url, params)
	if err != nil {
		return nil, internalerrors.New(code.ErrUnknown, err.Error())
	}
	err = json.Unmarshal(body, &obj)
	if err != nil {
		return nil, err
	}
	return obj, err
}

// 查询余额
func (b *balanceSrv) FindBalance(ctx context.Context, onBehalfOf string) (*api.FindBalanceRes, error) {
	var (
		url    = global.ViperObj.GetString("forex.baseUrl") + "/v2/balances/find"
		err    error
		body   []byte
		obj    *api.FindBalanceRes
		params = make(map[string]string)
	)
	params["on_behalf_of"] = onBehalfOf
	body, err = GetRequestToCC(ctx, url, params)
	if err != nil {
		return nil, internalerrors.New(code.ErrUnknown, err.Error())
	}
	err = json.Unmarshal(body, &obj)
	if err != nil {
		return nil, err
	}
	return obj, err
}

func (b *balanceSrv) TopUpMargin(ctx context.Context, req *api.TopUpMarginReq) (*api.TopUpMarginRes, error) {
	var (
		url  = global.ViperObj.GetString("forex.baseUrl") + "/v2/balances/top_up_margin"
		err  error
		body []byte
		obj  *api.TopUpMarginRes
	)
	payload := &bytes.Buffer{}
	writer := multipart.NewWriter(payload)
	_ = writer.WriteField("currency", req.Currency)
	_ = writer.WriteField("amount", req.Amount)
	if len(req.OnBehalfOf) > 0 {
		_ = writer.WriteField("on_behalf_of", req.OnBehalfOf)
	}
	if err = writer.Close(); err != nil {
		return nil, internalerrors.New(code.ErrUnknown, err.Error())
	}
	body, err = PostRequestToCC(ctx, url, writer.FormDataContentType(), payload)
	if err != nil {
		return nil, internalerrors.New(code.ErrUnknown, err.Error())
	}
	if err = json.Unmarshal(body, &obj); err != nil {
		return nil, internalerrors.New(code.ErrUnknown, err.Error())
	}
	return obj, nil
}
